package com.ziiwee.reduce.describe.creators.controllers;

import com.ziiwee.reduce.describe.DescribeException;
import com.ziiwee.reduce.describe.HandlerDescribe;
import com.ziiwee.reduce.describe.creators.handlers.ControllerHandlerDescribeCreator;
import com.ziiwee.reduce.describe.utils.DescribeUtil;
import com.ziiwee.reduce.rest.ResourceController;
import com.ziiwee.reduce.rest.ResourceService;
import org.springframework.beans.BeanUtils;
import org.springframework.core.ResolvableType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author ziiwee
 * @data 2020/8/12
 */
public class ResourceControllerControllerDescribeCreator extends AbstractControllerDescribeCreator {

    private final ResourceController<?, ?> controller;
    private final Map<RequestMappingInfo, HandlerMethod> mappings;
    private final ResourceService<?, ?> service;
    private final ResolvableType type;
    private final ResolvableType subjectType;
    private final ResolvableType idType;

    public ResourceControllerControllerDescribeCreator(ResourceController<?, ?> controller, ResolvableType type, Map<RequestMappingInfo, HandlerMethod> mappings) {
        this.controller = controller;
        this.mappings = mappings;
        this.service = controller.getService();
        this.type = type;
        List<ResolvableType> args = DescribeUtil.getTypeArgsByResolvableType(type, ResourceService.class);
        if (args.size() != 2) {
            throw new DescribeException("错误的 RestfulService ,无法获取泛型参数:" + type);
        }
        this.subjectType = args.get(0);
        this.idType = args.get(1);
    }


    @Override
    public AnnotatedElement getElement() {
        return subjectType.resolve();
    }

    @Override
    public ResolvableType getDefaultType() {
        return type;
    }

    @Override
    public List<HandlerDescribe> getHandlers() {
        boolean isCommonService = true;
        List<ResolvableType> args = DescribeUtil.getTypeArgsByResolvableType(ResolvableType.forInstance(service), ResourceService.class);
        if (args.size() == 2 && Objects.equals(args.get(0), subjectType) && Objects.equals(args.get(1), idType)) {
            isCommonService = false;
        }
        String basePattern = getBasePattern();
        List<HandlerDescribe> handlers = DescribeUtil.createHandlers(basePattern,service, subjectType, idType, isCommonService);
        Method[] declaredMethods = controller.getClass().getDeclaredMethods();
        mappings.forEach((k, v) -> {
            if (Arrays.stream(declaredMethods).anyMatch(it -> v.getMethod().equals(it))) {
                handlers.add(new ControllerHandlerDescribeCreator(k, v).create());
            }
        });
        return handlers;
    }

    @Override
    public ResolvableType getSubjectType() {
        return subjectType;
    }

    @Override
    public String getId() {
        return subjectType.toString();
    }

    private String getBasePattern(){
        for (RequestMapping requestMapping : Objects.requireNonNull(getType().resolve()).getAnnotationsByType(RequestMapping.class)) {
            for (String s : requestMapping.value()) {
                return s;
            }
        }
        return null;
    }
}
